/**
 *  EChatIMSDK .
 *  config:{
 *      host: easyIM 服务器
 *      key: sdk key
 *      secret: sdk secret.
 *      apiTransport: API 通讯方式(SOCKET|HTTP)
 *  }
 *
 * */
import { ISocket, socket } from "./Socket";
import Logger from "../../log/Logger";
import UserLoginForm from "../../model/form/UserLoginForm";
import ApiResponse from "../apis/ApiResponse";
import EChatIMApis from "../apis/EChatIMApis";
import { jwtCache } from "../cache/jwt";
import UserFriendListDTO from "../../model/dto/UserFriendListDTO";
import HistorySessionDTO from "../../model/dto/HistorySessionDTO";
import UserBlackForbidListDTO from "../../model/dto/UserBlackForbidListDTO";
import RoomListDTO from "../../model/dto/RoomListDTO";
import MessageReceiveDTO from "../../model/dto/MessageReceiveDTO";
import { Topic } from "../../common/Topic";
// import RoomListForm from "../../model/form/RoomListForm";
import UserBlackForbidListForm from "../../model/form/UserBlackForbidListForm";
import UserFriendListForm from "../../model/form/UserFriendListForm";
import HistoryListSessionForm from "../../model/form/HistoryListSessionForm";
import RoomListJoinForm from "../../model/form/RoomListJoinForm";
import UserListDTO from "../../model/dto/UserListDTO";
import UserListForm from "../../model/form/UserListForm";
import ClientUserOnlineForm from "../../model/form/ClientUserOnlineForm";
import { FileServerClientFactory, FileServerConfig, IFileServerClient } from "../fileclient/FileServerClient";


export interface IEChatIMSDKListener {
    onConnected():void; // 客户端已连接
    onDisConnected():void; // 客户端失去连接
    onUserInfo(userInfo: UserListDTO); // 获取用户信息
    onMessageReceive(message: MessageReceiveDTO); // 用户接收到消息
    onEventReceive(message: MessageReceiveDTO); // 用户接收到消息
    onSessionList(list:Array<HistorySessionDTO>):void; // 初始化加载会话列表
    onFriendList(list:Array<UserFriendListDTO>):void; // 初始化加载好友列表
    onBlacklistForbidList(list:Array<UserBlackForbidListDTO>):void; // 初始化加载黑白单, 禁言列表
    onRoomList(list:Array<RoomListDTO>):void; // 初始化加载群组列表

    onError(e:any):void;// 异常回调
}



export class EChatIMSDKConfig {
    host:string = "";
    socketPort:number = 9091;
    httpPort:number = 80;
    key:string = "";
    secret:string = "";
    apiTransport:string = "";
    loginAuid:string = "";
    loginToken:string = "";
    fileServerConfig:FileServerConfig|any = null;
    listeners: IEChatIMSDKListener|any = null;
}



export class EChatIMSDKState extends EChatIMSDKConfig{
    socketConnected: boolean = false;
    transport: string = 'HTTP';
}

export class EChatIMSDK {


    /**
     *  EChatIMSDK .
     *  config:{
     *      host: easyIM 服务器
     *      key: sdk key
     *      secret: sdk secret.
     *      apiTransport: API 通讯方式(SOCKET|HTTP)
     *
     *  }
     *
     *  export apiSocket, http.
     * */

    config: EChatIMSDKConfig = new EChatIMSDKConfig();
    socketConnected: boolean = false;
    logined: boolean = false;
    transport: string = 'HTTP';
    apis: EChatIMApis|any = null;

    init(config:EChatIMSDKConfig, callback: (sdk:EChatIMSDK) => void): EChatIMSDK {
        const self = this;
        self.apis = EChatIMApis;
        self.config.host = config.host ? config.host : 'localhost';
        self.config.socketPort = config.socketPort ? config.socketPort : 80;
        self.config.httpPort = config.httpPort ? config.httpPort : 80;
        self.transport = config.apiTransport ? config.apiTransport : 'HTTP';
        self.config.key = config.key;
        self.config.secret = config.secret;
        self.config.loginToken = config.loginToken;
        self.config.loginAuid = config.loginAuid;
        self.config.listeners = config.listeners; // 应用配置的监听器
        self.config.fileServerConfig = config.fileServerConfig;
        // TODO: verify sdk with key,secret.
        Logger.info(`ready to connect:${'http://' + self.config.host + ':' + self.config.socketPort}`);

        // handler default event for apiSocket.
        let firstInit: boolean = false;// 第一次初始化
        socket.connect('http://' + self.config.host + ':' + self.config.socketPort);
        socket.listen('connect', function(msg: any) {
            msg = msg;
            Logger.info('apiSocket.io connected!');
            self.socketConnected = true;
            if(!firstInit){
                callback(self);
                firstInit = true;
            }
            // 连接时自动登录
            self.autoLogin(function () {
                self.logined = true;
                if(self.config.listeners){
                    self.initConfigListener();
                }
            });
            if(self.config.listeners && typeof self.config.listeners.onConnected === 'function'){
                self.config.listeners.onConnected();
            }
        });
        socket.listen('disconnect', function(msg: any) {
            msg = msg;
            Logger.info('apiSocket.io disconnected!');
            self.socketConnected = false;
            self.logined = false;
            if(self.config.listeners && typeof self.config.listeners.onDisConnected === 'function'){
                self.config.listeners.onDisConnected();
            }
        });


        return this;
    }

    public newFileClient():IFileServerClient {
        // 文件服务器
        if(this.config.fileServerConfig){
            return FileServerClientFactory.create(this.config.fileServerConfig, this.config.key);
        }
        else {
            throw new Error('没有fileServerConfig配置, 无法创建file client 实例');
        }
    }

    // when socket connect with the server, auto login
    public autoLogin(finishHandler:()=>void): void {
        if(!this.config.key || !this.config.loginAuid || !this.config.loginToken){
            return;
        }
        const self = this;
        const form = new UserLoginForm();
        form.auid = this.config.loginAuid;
        form.token = this.config.loginToken;
        form.appKey = this.config.key;
        EChatIMApis.login.call(form).then((res:ApiResponse<string>)=>{
            Logger.info('auto Login ok');
            if(res.isSucceed()){
                if(!res.data){
                    throw Error('server not return jwt yet.');
                }
                jwtCache.jwt = res.data!.toString();
                if(typeof finishHandler === 'function'){
                    finishHandler();
                }
            }
            else {
                throw Error('get jwt failed.');
            }
        }).catch((e:any)=>{
            Logger.error('apiSocket.io disconnected!');
            Logger.trace(e);
            this.getSocket().disConnect();
            if(typeof self.config.listeners.onError === 'function'){
                self.config.listeners.onError(e);
            }
        });
    }

    public getState(): EChatIMSDKState | any{
        if(!this.config){
            throw Error('EChatIMSDK not config yet.');
        }
        return {
            socketConnected: this.socketConnected,
            transport: this.transport,
            ...this.config
        }
    }
    public getSocket(): ISocket{
        return socket;
    }

    private initConfigListener(){
        if(!this.config.listeners){
            return;
        }
        const self = this;
        if(typeof this.config.listeners.onMessageReceive === 'function' || typeof this.config.listeners.onEventReceive === 'function'){
            self.getSocket().listen(Topic.APP_DOWNSTREAM_MESSAGE.topic_name, function(message){
                if(message.method === Topic.APP_DOWNSTREAM_MESSAGE.METHOD.SEND_MESSAGE_TO_CLIENT){
                    if(typeof self.config.listeners.onMessageReceive === 'function'){
                        self.config.listeners.onMessageReceive(message);
                    }
                }
                else if(message.method === Topic.APP_DOWNSTREAM_MESSAGE.METHOD.SEND_EVENT_TO_CLIENT){
                    if(typeof self.config.listeners.onEventReceive === 'function'){
                        self.config.listeners.onEventReceive(message);
                    }
                }
            });
        }

        if(typeof this.config.listeners.onUserInfo === 'function'){
            const userListForm = new UserListForm();
            userListForm.auids = [self.config.loginAuid];
            EChatIMApis.userList.call(userListForm).then((response)=>{
                if(response.data.length > 0){
                    self.config.listeners.onUserInfo(response.data[0]);
                }
                else {
                    throw new Error("无法找到登录用户IM信息.");
                }
            }).catch((e)=>{
                Logger.trace(e);
            })
        }
        if(typeof this.config.listeners.onSessionList === 'function'){
            const historyListSessionForm = new HistoryListSessionForm();
            historyListSessionForm.auid = self.config.loginAuid;
            historyListSessionForm.startTimestamp = 0;
            historyListSessionForm.endTimestamp = new Date().getTime();
            EChatIMApis.historyListSession.call(historyListSessionForm).then((response)=>{
                const form = new ClientUserOnlineForm();
                const sessions = (response.data as Array<any>);
                form.auids = sessions.map(function (v) {
                    return v.toTarget;
                });
                if(form.auids.length === 0){
                    return;
                }
                EChatIMApis.userOnline.call(form).then(resp=>{
                    const userOnlineMapByAuid = {};
                    (resp.data as Array<any>).forEach(vv => userOnlineMapByAuid[vv.auid] = vv);
                    sessions.forEach(session => {
                        session.online = userOnlineMapByAuid.hasOwnProperty(session.toTarget) ? userOnlineMapByAuid[session.toTarget].online : 0
                    });

                    self.config.listeners.onSessionList(sessions);
                }).catch((e)=>{
                    Logger.trace(e);
                    if(typeof self.config.listeners.onError === 'function'){
                        self.config.listeners.onError(e);
                    }
                })

                // self.config.listeners.onSessionList(response.data);
            }).catch((e)=>{
                Logger.trace(e);
            })
        }

        if(typeof this.config.listeners.onFriendList === 'function'){
            const userFriendListForm = new UserFriendListForm();
            userFriendListForm.auid = self.config.loginAuid;
            EChatIMApis.listFriends.call(userFriendListForm).then((response)=>{
                const form = new ClientUserOnlineForm();
                const friends = (response.data as Array<any>);
                form.auids = friends.map(function (v) {
                    return v.auid;
                });
                if(form.auids.length === 0){
                    return;
                }
                EChatIMApis.userOnline.call(form).then(resp=>{
                    const userOnlineMapByAuid = {};
                    (resp.data as Array<any>).forEach(vv => userOnlineMapByAuid[vv.auid] = vv);
                    friends.forEach(friend => {
                        friend.online = userOnlineMapByAuid.hasOwnProperty(friend.auid) ? userOnlineMapByAuid[friend.auid].online : 0
                    });

                    self.config.listeners.onFriendList(friends);
                }).catch((e)=>{
                    Logger.trace(e);
                    if(typeof self.config.listeners.onError === 'function'){
                        self.config.listeners.onError(e);
                    }
                })

                // self.config.listeners.onFriendList(response.data);
            }).catch((e)=>{
                Logger.trace(e);
                if(typeof self.config.listeners.onError === 'function'){
                    self.config.listeners.onError(e);
                }
            })
        }

        if(typeof this.config.listeners.onBlacklistForbidList === 'function'){
            const userBlackForbidListForm = new UserBlackForbidListForm();
            userBlackForbidListForm.auid = self.config.loginAuid;
            EChatIMApis.listBlackListForbid.call(userBlackForbidListForm).then((response)=>{
                self.config.listeners.onBlacklistForbidList(response.data);
            }).catch((e)=>{
                Logger.trace(e);
                if(typeof self.config.listeners.onError === 'function'){
                    self.config.listeners.onError(e);
                }
            })
        }

        if(typeof this.config.listeners.onRoomList === 'function'){
            // TODO: get user's room joined
            const roomListJoinForm = new RoomListJoinForm();
            roomListJoinForm.auid = self.config.loginAuid;
            EChatIMApis.listRoomJoin.call(roomListJoinForm).then((response)=>{
                self.config.listeners.onRoomList(response.data);
            }).catch((e)=>{
                Logger.trace(e);
                if(typeof self.config.listeners.onError === 'function'){
                    self.config.listeners.onError(e);
                }
            })
        }
    }
}

export const echatIMSDK = new EChatIMSDK();


